const path = require('path');
const { ProgressPlugin } = require('webpack');
const glob = require('glob')
const CompressionWebpackPlugin = require("compression-webpack-plugin");

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const PurgecssPlugin = require('purgecss-webpack-plugin')

const TerserPlugin = require("terser-webpack-plugin");
// const CopyWebpackPlugin = require("copy-webpack-plugin");
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
// add-asset-html-webpack-plugin 会有拷贝功能


const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin');
const notifier = require('node-notifier');
const ICON = path.join(__dirname, 'icon.png');

const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const smw = new SpeedMeasureWebpackPlugin();
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const HtmlWebpackPlugin = require('html-webpack-plugin');

let config = {
  context: process.cwd(),
  entry: {
    app: "./src/index.js"
  },
  output: {
    path: path.resolve(__dirname, './dist'), // 一定是绝对路径
    filename: "[name].[contenthash].js?v=[contenthash:8]"
  },
  // noParse: /title.js/, // 配置的不会解析依赖的模块.比如title.js中不能有依赖其他模块，就是说不能有 import，require引入其他的库或模块
  resolve: {
    extensions: [".js", ".jsx", ".json"], //指定查找文件名，不指定也可以就是编写代码时写上后缀名 这定义了引入模块是，可以省略的后缀名
    alias: { // 指定查找别名
      "@": path.resolve(__dirname, "src")
    },
    modules: ["node_modules"], // 指定模块查找的目录
    mainFields: ["module", "main"], // 指定从库的 package.json 中配置的属性查找，默认是 main
    mainFiles: ["index"] // 如果 mainFields 中的找不到，默认查找库中根目录下的 index.js 文件
  },
  externals: {
    // 不需要打包的模块, 比如通过 copy-webpack-plugin 拷贝的，或者 cdn 引入的
    jquery: 'jQuery',
    lodash: {
      commonjs: 'lodash',
      amd: 'lodash',
      root: '_', // indicates global variable
    },
    react: 'react',
  },
  plugins: [
    new ProgressPlugin(), // 启动进度条
    // 错误提示
    new FriendlyErrorsWebpackPlugin({
      onErrors: (severity, errors) => {
        if (severity !== 'error') {
          return;
        }
        const error = errors[0];
        notifier.notify({
          title: "Webpack 编译失败",
          message: severity + ': ' + error.name,
          subtitle: error.file || '',
          icon: ICON
        });
      }
    }),
    new HtmlWebpackPlugin({
      title: 'Custom template',
      template: 'index.html',
      filename: 'index.html',
      inject: true,
    }),
    // new CopyWebpackPlugin({
    //   patterns: [
    //     { from: "public", to: "lib" },
    //   ],
    // })
    new AddAssetHtmlPlugin({
      filepath: require.resolve(path.resolve(__dirname, './public/jquery.js'))
    }),
  ]
};


if (process.env.NODE_ENV === "production") {
  config = {
    ...config,
    mode: "production",
    devtool: 'source-map', // 不配置的话，默认是 eval 处理的，对热更新友好
    module: {
      rules: [
        {
          oneOf: [
            {
              test: /\.m?js$/,
              // exclude: /(node_modules|bower_components)/,
              include: path.resolve(__dirname, 'src'), //  尽量使用 include
              use: {
                loader: 'babel-loader',
                options: {
                  cacheDirectory: true,
                  presets: ['@babel/preset-env']
                }
              }
            },
            {
              test: /.s?css$/i,
              use: [
                MiniCssExtractPlugin.loader,
                'css-loader',
                'postcss-loader',
                'sass-loader'
              ]
            }
          ]
        }
      ]
    },
    optimization: {
      minimize: true,
      minimizer: [
        new CssMinimizerPlugin(),
        new TerserPlugin()
      ],
    },
    plugins: config.plugins.concat([
      new ProgressPlugin(), // 启动进度条
      new CleanWebpackPlugin(), // 清除dist文件夹
      // 错误提示
      new FriendlyErrorsWebpackPlugin({
        onErrors: (severity, errors) => {
          if (severity !== 'error') {
            return;
          }
          const error = errors[0];
          notifier.notify({
            title: "Webpack 编译失败",
            message: severity + ': ' + error.name,
            subtitle: error.file || '',
            icon: ICON
          });
        }
      }),
      new BundleAnalyzerPlugin({  // 可以查看打包后的文件大小
        analyzerMode: 'disabled', // 不启动HTTP静态服务
        generateStatsFile: true, // 生成stats.json文件
      }),
      // new PurgecssPlugin({ // 使用他可能有一些样式处理了，注意使用
      //   paths: glob.sync(`src/**/*`, { nodir: true }),
      // }),

      new MiniCssExtractPlugin({ // 将css提取到单独的文件中
        linkType: "text/css",
      }),

      new CompressionWebpackPlugin(), // gzip
    ])
  }
} else {
  config = smw.wrap({
    ...config,
    mode: "development",
    context: process.cwd(),
    devtool: 'source-map', // 不配置的话，默认是 eval 处理的，对热更新友好
    devServer: {
      static: {
        directory: path.join(__dirname, 'public'),
      },
      compress: true,
      port: 9000,
      open: true,
      historyApiFallback: true,
      client: {
        overlay: true,
      },
    },
    module: {
      rules: [
        {
          test: /\.m?js$/,
          // exclude: /(node_modules|bower_components)/,
          include: path.resolve(__dirname, 'src'), //  尽量使用 include
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        },
        {
          oneOf: [ //  配置多个一样的test 就找到就不在继续了
            {
              test: /.s?css$/i,
              use: [
                'style-loader',
                'css-loader',
                'postcss-loader',
                'sass-loader'
              ]
            }
          ]
        }
      ]
    },
    plugins: config.plugins.concat([])
  })
}

module.exports = config;